/*
 * Copyright (c) 2000-2005 Apple Computer, Inc. All rights reserved.
 *
 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
 * 
 * This file contains Original Code and/or Modifications of Original Code
 * as defined in and that are subject to the Apple Public Source License
 * Version 2.0 (the 'License'). You may not use this file except in
 * compliance with the License. The rights granted to you under the License
 * may not be used to create, or enable the creation or redistribution of,
 * unlawful or unlicensed copies of an Apple operating system, or to
 * circumvent, violate, or enable the circumvention or violation of, any
 * terms of an Apple operating system software license agreement.
 * 
 * Please obtain a copy of the License at
 * http://www.opensource.apple.com/apsl/ and read it before using this file.
 * 
 * The Original Code and all software distributed under the License are
 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
 * Please see the License for the specific language governing rights and
 * limitations under the License.
 * 
 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
 */
/* Copyright (c) 1995 NeXT Computer, Inc. All Rights Reserved */
/*
 * Copyright (c) 1989, 1993, 1995
 *	The Regents of the University of California.  All rights reserved.
 *
 * This code is derived from software contributed to Berkeley by
 * Rick Macklem at The University of Guelph.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by the University of
 *	California, Berkeley and its contributors.
 * 4. Neither the name of the University nor the names of its contributors
 *    may be used to endorse or promote products derived from this software
 *    without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 */
/*
 * This file includes modifications of code found in the Apple XNU Kernel
 * and has been modifed for use in this Kext by Rick Macklem, May 2006.
 */

/*
 * These macros handle nfsvattr fields. They look a bit silly here, but
 * are quite different for the Darwin port.
 */
#define	NFSVNO_ATTRINIT(n)		VATTR_INIT(&((n)->na_va))
#define	NFSVNO_SETATTRVAL(n, f, v)	VATTR_SET(&((n)->na_va), va_##f, (v))
#define	NFSVNO_SETACTIVE(n, f)
#define	NFSVNO_UNSET(n, f)		VATTR_CLEAR_ACTIVE(&((n)->na_va), va_##f)
#define	NFSVNO_NOTSETMODE(n)		(!VATTR_IS_ACTIVE(&((n)->na_va), va_mode))
#define	NFSVNO_ISSETMODE(n)		VATTR_IS_ACTIVE(&((n)->na_va), va_mode)
#define	NFSVNO_NOTSETUID(n)		(!VATTR_IS_ACTIVE(&((n)->na_va), va_uid))
#define	NFSVNO_ISSETUID(n)		VATTR_IS_ACTIVE(&((n)->na_va), va_uid)
#define	NFSVNO_NOTSETGID(n)		(!VATTR_IS_ACTIVE(&((n)->na_va), va_gid))
#define	NFSVNO_ISSETGID(n)		VATTR_IS_ACTIVE(&((n)->na_va), va_gid)
#define	NFSVNO_NOTSETSIZE(n)		(!VATTR_IS_ACTIVE(&((n)->na_va), va_data_size))
#define	NFSVNO_ISSETSIZE(n)		VATTR_IS_ACTIVE(&((n)->na_va), va_data_size)
#define	NFSVNO_NOTSETATIME(n)		(!VATTR_IS_ACTIVE(&((n)->na_va), va_access_time))
#define	NFSVNO_ISSETATIME(n)		VATTR_IS_ACTIVE(&((n)->na_va), va_access_time)
#define	NFSVNO_NOTSETMTIME(n)		(!VATTR_IS_ACTIVE(&((n)->na_va), va_modify_time))
#define	NFSVNO_ISSETMTIME(n)		VATTR_IS_ACTIVE(&((n)->na_va), va_modify_time)

/*
 * New NFS Server File Handle structures
 */
#define	NFSRV_MAXFH	NFSX_V4FHMAX

/* NFS export handle identifies which NFS export */
#define	NEWNFS_FH_VERSION	0x4e590000
struct newnfs_exphandle {
	uint32_t	nxh_version;		/* data structure version */
	uint32_t	nxh_fsid;		/* File System Export ID */
	uint32_t	nxh_expid;		/* Export ID */
	uint16_t	nxh_flags;		/* export handle flags */
	uint8_t		nxh_reserved;		/* future use */
	uint8_t		nxh_fidlen;		/* length of File ID */
};

/* nxh_flags */
#define NXHF_INVALIDFH		0x0001		/* file handle is invalid */

#define	NEWNFS_MAX_FID_SIZE	(NFSRV_MAXFH - sizeof(struct newnfs_exphandle))
#define	NEWNFSV2_MAX_FID_SIZE	(NFSX_V2FH - sizeof(struct newnfs_exphandle))

/* NFS server internal view of fhandle_t */
struct newnfs_filehandle {
	int			nfh_len;	/* total length of file handle */
	struct newnfs_exphandle	nfh_xh;		/* export handle */
	unsigned char		nfh_fid[NEWNFS_MAX_FID_SIZE]; /* File ID */
};

/*
 * NFS export data structures
 */

struct nenwfs_export_net_args {
	uint32_t		nxna_flags;	/* export flags */
	struct xucred		nxna_cred;	/* mapped credential for root/all user */
	struct sockaddr_storage	nxna_addr;	/* net address to which exported */
	struct sockaddr_storage	nxna_mask;	/* mask for net address */
};

struct newnfs_export_args {
	uint32_t		nxa_fsid;	/* export FS ID */
	uint32_t		nxa_expid;	/* export ID */
	char			*nxa_fspath;	/* export FS path */
	uint32_t		nxa_flags;	/* export arg flags */
	uint32_t		nxa_netcount;	/* #entries in ex_nets array */
	struct newnfs_export_net_args *nxa_nets;	/* array of net args */
};

/* LP64 version of export_args */

#if __DARWIN_ALIGN_NATURAL
#pragma options align=natural
#endif

struct user_newnfs_export_args {
	uint32_t		nxa_fsid;	/* export FS ID */
	uint32_t		nxa_expid;	/* export ID */
	user_addr_t		nxa_fspath;	/* export FS path */
	user_addr_t		nxa_exppath;	/* export sub-path */
	uint32_t		nxa_flags;	/* export arg flags */
	uint32_t		nxa_netcount;	/* #entries in ex_nets array */
	user_addr_t		nxa_nets;	/* array of net args */
};

#if __DARWIN_ALIGN_NATURAL
#pragma options align=reset
#endif


/* nfs export arg flags */
#define NXA_DELETE		0x0001	/* delete the specified export(s) */
#define NXA_ADD			0x0002	/* add the specified export(s) */
#define NXA_REPLACE		0x0003	/* delete and add the specified export(s) */
#define NXA_DELETE_ALL		0x0004	/* delete all exports */

/* export option flags */
#define NX_READONLY		0x0001	/* exported read-only */
#define NX_DEFAULTEXPORT	0x0002	/* exported to the world */
#define NX_MAPROOT		0x0004	/* map root access to anon credential */
#define NX_MAPALL		0x0008	/* map all access to anon credential */
#define NX_KERB			0x0010	/* exported with Kerberos uid mapping */
#define NX_32BITCLIENTS		0x0020	/* restrict directory cookies to 32 bits */

struct newnfs_export_options {
	uint32_t		nxo_flags;	/* export options */
	kauth_cred_t		nxo_cred;	/* mapped credential */
};

/* Network address lookup element and individual export options */
struct newnfs_netopt {
	struct radix_node		no_rnodes[2];	/* radix tree glue */
	struct newnfs_export_options	no_opt;		/* export options */
};

/* Network export information */
/*
 * Darwin8 allows exporting of subdirs in file systems. I don't allow
 * this because it screws up the one<->one mapping of file handles to files
 * when there are multiple hard links to a file in different dirs.
 * (Maybe the Darwin8 fs's don't support multiple hard links?)
 */
struct newnfs_exportfs {
	LIST_ENTRY(newnfs_exportfs)	nxfs_next;	/* exported file system list */
	LIST_ENTRY(newnfs_exportfs)	nxfs_hash;	/* export hash chain */
	uint32_t			nxfs_id;	/* file system ID */
	uint32_t			nxfs_expid;	/* exported file system ID */
	char				*nxfs_path;	/* exported file system path */
	uint32_t			nxfs_flags;	/* export flags */
	struct newnfs_filehandle	nxfs_fh;	/* export root file handle */
	struct newnfs_export_options	nxfs_defopt;	/* default options */
	uint32_t			nxfs_expcnt;	/* # exports in table */
	struct radix_node_head		*nxfs_rtable[AF_MAX+1]; /* table of exports (netopts) */
};

#define	NFSEXPHASHVAL(FSID, EXPID)					\
	(((FSID) >> 24) ^ ((FSID) >> 16) ^ ((FSID) >> 8) ^ (EXPID))
#define	NFSEXPHASH(FSID, EXPID)						\
	(&nfsexphashtbl[NFSEXPHASHVAL((FSID),(EXPID)) & nfsexphash])

struct nfsexstuff {
	struct newnfs_export_options	*nes_nxo;
	int nes_vfslocked;
};

#define	NFSVNO_EXINIT(e)		((e)->nes_nxo->nxo_flags = 0)
#define	NFSVNO_EXPORTED(e)		((e)->nes_nxo->nxo_flags & NX_EXPORTED)
#define	NFSVNO_EXRDONLY(e)		((e)->nes_nxo->nxo_flags & NX_READONLY)
#define	NFSVNO_EXMANDLOCK(e)		((e)->nes_nxo->nxo_flags & NX_MANDLOCK)
#define	NFSVNO_EXNODELEG(e)		((e)->nes_nxo->nxo_flags & NX_NODELEG)
#define	NFSVNO_EXNORDDELEG(e)		((e)->nes_nxo->nxo_flags & NX_NORDDELEG)
#define	NFSVNO_EXSTRICTACCESS(e)	((e)->nes_nxo->nxo_flags & NX_STRICTACCESS)
#define	NFSVNO_EXGSSONLY(e)		((e)->nes_nxo->nxo_flags & NX_GSSONLY)

#define	NFSVNO_SETEXRDONLY(e)		((e)->nes_nxo->nxo_flags = NX_READONLY)

/* export option flags */
#define NX_READONLY		0x0001	/* exported read-only */
#define NX_DEFAULTEXPORT	0x0002	/* exported to the world */
#define NX_MAPROOT		0x0004	/* map root access to anon credential */
#define NX_MAPALL		0x0008	/* map all access to anon credential */
#define NX_KERB			0x0010	/* exported with Kerberos uid mapping */
#define	NX_GSSONLY		NX_KERB
#define NX_32BITCLIENTS		0x0020	/* restrict directory cookies to 32 bits */
#define	NX_MANDLOCK		0x0040	/* enforce mandatory locking for NFSv4 */
#define	NX_NODELEG		0x0080	/* don't issue delegations */
#define	NX_NORDDELEG		0x0100	/* don't issue read delegations */
#define	NX_STRICTACCESS		0x0200	/* enforce strict access rules */
#define	NX_EXPORTED		0x0400	/* is exported */
#define	NX_V4ONLY		0x0800	/* NFSv4 only */

/*
 * Define these for Darwin, as there is no locked/unlocked vnode distinction
 * in the vfs.
 */
#define	vput(v)		vnode_put(v)
#define	vrele(v)	vnode_put(v)
#define	VOP_UNLOCK(v, f, p)
#define	vn_lock(v, f, p)

#define	NFSNAMEICNDSET(p, c, o, f)	do {					\
		(p)->cn_nameiop = (o);						\
		(p)->cn_flags = (f);						\
	} while (0)

#define	splsoftclock()	0
#define	splx(s)

#define	VREF(v)		((void) vnode_ref(v))

#define	NFSVNO_CMPFH(f1, f2)						\
    ((f1)->fh_len == (f2)->fh_len &&					\
     !bcmp((f1)->fh_data, (f2)->fh_data, (f1)->fh_len))

#define	NFSLOCKHASH(f) 							\
	(&nfslockhash[(*((u_int32_t *)((f)->fh_data))) % NFSLOCKHASHSIZE])

#define	NFSFPVNODE(p)	((struct vnode *)((p)->f_fglob->fg_data))
#define	NFSFPCRED(p)	((p)->f_fglob->fg_cred)
#define	NFSFPFLAG(p)	((p)->f_fglob->fg_flag)

int groupmember(gid_t gid, kauth_cred_t cred);

#define	NFSRV_MINFH	4		/* arbitrary, defined by local fs */

/*
 * Define a structure similar to ufs_args for use in exporting the V4 root.
 */
struct nfsex_args {
	char	*fspec;
};

